package com.fadadianqi.logistics.admin.controller;

import com.fadadianqi.logistics.admin.controller.form.AjaxResult;
import com.fadadianqi.logistics.admin.controller.form.GoodsForm;
import com.fadadianqi.logistics.admin.controller.vo.GoodsVO;
import com.fadadianqi.commons.BackToURLUtils;
import com.fadadianqi.commons.JSONProvider;
import com.fadadianqi.goods.model.*;
import com.fadadianqi.goods.service.GoodsService;
import com.yeqiangwei.commons.util.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.MessageSource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.support.SessionStatus;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;

import static com.fadadianqi.logistics.admin.controller.URIMappingUtils.INVENTORY_PREFIX;

@Controller("admin_goodsController")
public class GoodsController {

    private static final Log log = LogFactory.getLog(GoodsController.class);

    private static final String URI_AJAX_SAVE = INVENTORY_PREFIX + "/ajax/goods/save";
    private static final String URI_AJAX_GET = INVENTORY_PREFIX + "/ajax/goods/{id}";

    private static final String URI_AJAX_LIST = INVENTORY_PREFIX
            + "/ajax/goods/list";
    private static final String VIEW_AJAX_LIST = "admin/goods/ajaxList";

    private static final String COMMAND_NAME = "goodsForm";

    private static final String PARAM_BRAND_ID = "bid";
    private static final String PARAM_CATEGORY_ID = "cid";
    private static final String PARAM_BACK_URL = "backURL";

    @RequestMapping(value = "/a/goods/save", method = RequestMethod.POST)
    public String save(@ModelAttribute("form") GoodsForm form,
                       BindingResult result, SessionStatus status,
                       HttpServletRequest request,
                       HttpServletResponse response, ModelMap modelMap) {

        Goods goods = goodsService.getGoodsById(form.getId());
        if (goods == null) {
            goods = new Goods();
        }
        BeanUtils.copyProperties(goods, form);
        try {
            goodsService.saveGoods(goods, form.getProps());
        } catch (Exception e) {
            log.error(e.toString());
        }
        FormBuf buf = new FormBuf();
        buf.setBrandId(goods.getBrandId());
        buf.setCategoryId(goods.getCategoryId());
        buf.setGoodsId(goods.getId());
        saveFormBuf(request, response, buf);

        String backURL = ParamUtils.getString(request, PARAM_BACK_URL, null);

        if (null != backURL) {
            return "redirect:" + backURL;
        } else {
            return "redirect:/a/goods/list";
        }
    }

    @RequestMapping(value = "/a/goods/form", method = RequestMethod.GET)
    public String showForm(HttpServletRequest request, ModelMap modelMap) {

        BackToURLUtils.setParamURLToAttr(request, PARAM_BACK_URL);

        String id = ParamUtils.getString(request, "id", null);
        Goods goods = goodsService.getGoodsById(id);
        GoodsForm form = new GoodsForm();
        if (goods != null) {
            BeanUtils.copyProperties(form, goods);
        }
        modelMap.put("goodsForm", form);

        List<Category> categoryList = goodsService.findAllCategory();
        modelMap.put("categoryList", categoryList);

        List<Brand> brandList = goodsService.findAllBrand();
        modelMap.put("brandList", brandList);

        FormBuf buf = getFormBuf(request);
        if (buf == null) {
            buf = new FormBuf();
        }
        if (goods != null) {
            BeanUtils.copyProperties(buf, goods);
            Brand brand = goodsService.getBrandById(goods.getBrandId());
            if (brand != null) {
                buf.setBrandName(brand.getName());
            }
            Category category = goodsService.getCategoryById(goods.getCategoryId());
            if (category != null) {
                buf.setCategoryName(category.getName());
            }
            List<GoodsPropValue> goodsPropValues = goodsService.findGoodsPropValueByGoodsId(goods.getId());
            modelMap.put("goodsPropValues", goodsPropValues);
        }
        modelMap.put("formBuf", buf);

        return "/admin/goods/form";
    }


    @RequestMapping(value = "/a/goods/list", method = RequestMethod.GET)
    public String showList(HttpServletRequest request,
                           HttpServletResponse response,
                           ModelMap modelMap) {

        BackToURLUtils.setCurrentURLToAttr(request, PARAM_BACK_URL);

        Pagination pagination = new Pagination(request, 20);
        List<Goods> goodsList = null;

        String cid = ParamUtils.getString(request, PARAM_CATEGORY_ID, null);
        String bid = ParamUtils.getString(request, PARAM_BRAND_ID, null);

        HashMap<String, Object> elements = new HashMap<String, Object>();
        elements.put(PARAM_CATEGORY_ID, cid);
        elements.put(PARAM_BRAND_ID, bid);
        pagination.setElements(elements);
        Integer total = null;
        if (ValidatorHelper.isNotEmpty(bid) && ValidatorHelper.isNotEmpty(cid)) {
            goodsList = goodsService.findByBrandIdAndCategoryId(bid, cid, pagination);
            total = goodsService.countByBrandIdAndCategoryId(bid, cid);
        } else if (ValidatorHelper.isNotEmpty(cid)) {
            goodsList = goodsService.findByCategoryId(cid, pagination);
            total = goodsService.countByCategoryId(cid);
        } else if (ValidatorHelper.isNotEmpty(bid)) {
            goodsList = goodsService.findByBrandId(bid, pagination);
            total = goodsService.countByBrandId(bid);
        } else {
            goodsList = goodsService.findAllGoods(pagination);
            total = goodsService.countAll();
        }
        //
        if (ValidatorHelper.isNotEmpty(cid)) {
            List<?> props = goodsService.findPropsByCategoryId(cid);
            modelMap.put("props", props);
        }
        //
        pagination.setTotal(total);
        PaginationHelper.setAttribute(request, pagination);
        List<GoodsVO> goodsVOList = new ArrayList<GoodsVO>();
        for (Goods goods : goodsList) {
            GoodsVO vo = new GoodsVO();
            BeanUtils.copyProperties(vo, goods);
            Category category = goodsService.getCategoryById(goods.getCategoryId());
            String categoryName = category.getName();

            Brand brand = goodsService.getBrandById(goods.getBrandId());
            String brandName = brand.getName();

            vo.setCategoryName(categoryName);
            vo.setBrandName(brandName);

            List<GoodsPropValue> propValues = goodsService.findGoodsPropValueByGoodsId(vo.getId());
            vo.setPropValues(propValues);
            goodsVOList.add(vo);
        }

        modelMap.put("goodsVOList", goodsVOList);
        modelMap.put(PARAM_CATEGORY_ID, cid);
        modelMap.put(PARAM_BRAND_ID, bid);

        List<Category> categoryList = goodsService.findAllCategory();
        modelMap.put("categoryList", categoryList);

        List<Brand> brandList = goodsService.findAllBrand();
        modelMap.put("brandList", brandList);

        return "/admin/goods/list";
    }

    @RequestMapping(value = "/a/admin/goods/category-props/{id}", method = RequestMethod.GET)
    public String getCategoryProps(@PathVariable String id
            , HttpServletRequest request
            , HttpServletResponse response
            , ModelMap modelMap) {
        List<Properties> props = goodsService.findPropsByCategoryId(id);
        List<PropVO> pvs = new ArrayList<PropVO>();
        if (ValidatorHelper.isNotEmpty(props)) {
            for (Properties p : props) {
                PropVO v = new PropVO();
                BeanUtils.copyProperties(v, p);
                v.setValues(goodsService.findPropValues(p.getId()));
                pvs.add(v);
            }
        }
        modelMap.put("props", pvs);
        return "/admin/goods/category-props";
    }

    @RequestMapping(value = "/a/admin/goods/brands", method = RequestMethod.GET)
    public String showBrands(ModelMap modelMap) {
        List<Brand> brands = goodsService.findAllBrand();
        modelMap.put("brands", brands);
        return "/admin/goods/ajaxBrands";
    }

    @RequestMapping(value = "/a/admin/goods/categories", method = RequestMethod.GET)
    public String showCategories(ModelMap modelMap) {
        List<Category> categories = goodsService.findAllCategory();
        modelMap.put("categories", categories);
        return "/admin/goods/ajaxCategories";
    }


    @RequestMapping(value = URI_AJAX_GET, method = RequestMethod.GET)
    @ResponseBody
    public ResponseEntity<String> ajaxGet(@PathVariable String id
            , HttpServletRequest request, HttpServletResponse response) {

        Goods goods = goodsService.getGoodsById(id);
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.add("Content-Type", "text/html; charset=utf-8");
        GoodsJSON json = new GoodsJSON();
        BeanUtils.copyProperties(json, goods);
        json.setBrand(goodsService.getBrandById(goods.getBrandId()));
        json.setCategory(goodsService.getCategoryById(goods.getCategoryId()));
        AjaxResult rs = new AjaxResult(json, Boolean.TRUE, null);
        return new ResponseEntity<String>(JSONProvider.toJSON(rs),
                responseHeaders, HttpStatus.OK);
    }

    @RequestMapping(value = URI_AJAX_LIST, method = RequestMethod.GET)
    public String ajaxList(HttpServletRequest request, ModelMap modelMap) {

        String categoryId = ParamUtils.getString(request, PARAM_CATEGORY_ID, null);
        String brandId = ParamUtils.getString(request, PARAM_BRAND_ID, null);
        log.debug("#ajaxList#, categoryId: " + categoryId + ", brandId: " + brandId);
        List<Goods> list = null;
        Pagination pg = new Pagination(1, Integer.MAX_VALUE);
        if (brandId != null && categoryId != null) {
            pg.setOrderList(new Pagination.Order[]{Pagination.getNewOrder("recently_update", Boolean.FALSE)});
            list = goodsService.findByBrandIdAndCategoryId(brandId, categoryId, pg);
        } else if (brandId != null) {
            list = goodsService.findByBrandId(brandId, null);
        } else if (categoryId != null) {
            list = goodsService.findByCategoryId(categoryId, null);
        } else {
            list = goodsService.findAllGoods(pg);
        }
        if (ValidatorHelper.isNotEmpty(categoryId)) {
            List<?> props = goodsService.findPropsByCategoryId(categoryId);
            modelMap.put("props", props);
        }
        List<GoodsVO> goodsVOList = new ArrayList<GoodsVO>();
        for (Goods goods : list) {
            GoodsVO vo = new GoodsVO();
            BeanUtils.copyProperties(vo, goods);
            Category category = goodsService.getCategoryById(goods.getCategoryId());
            String categoryName = category.getName();
            Brand brand = goodsService.getBrandById(goods.getBrandId());
            String brandName = brand.getName();
            vo.setCategoryName(categoryName);
            vo.setBrandName(brandName);
            //
            List<GoodsPropValue> propValues = goodsService.findGoodsPropValueByGoodsId(vo.getId());
            vo.setPropValues(propValues);
            goodsVOList.add(vo);
        }
        modelMap.put("goodsVOList", goodsVOList);
        return VIEW_AJAX_LIST;
    }

    @RequestMapping(value = URI_AJAX_SAVE, method = RequestMethod.POST)
    @ResponseBody
    public ResponseEntity<String> ajaxSave(
            @ModelAttribute(COMMAND_NAME) GoodsForm form, BindingResult result,
            SessionStatus status) {
        if (log.isDebugEnabled()) {
            log.debug("#ajaxSave#, id: " + form.getId() + ", name: "
                    + form.getName());
        }
        AjaxResult rs = null;
        HttpHeaders responseHeaders = new HttpHeaders();
        responseHeaders.add("Content-Type", "text/html; charset=utf-8");
        if (ValidatorHelper.isEmpty(form.getBrandId())
                || ValidatorHelper.isEmpty(form.getCategoryId())) {
            String msg = messageSource.getMessage("remind.required.categoryId&&brandId", null, Locale.getDefault());
            rs = new AjaxResult(form, Boolean.FALSE, msg);
        } else {
            form.setPinyin(StringHelper.toPinyin(form.getName()));
            try {
                Goods goods = goodsService.getGoodsById(form.getId());
                if (goods == null) {
                    goods = new Goods();
                }
                BeanUtils.copyProperties(goods, form);
                goodsService.saveGoods(goods, form.getProps());
                status.setComplete();
                form.setId(goods.getId());
                String msg = messageSource.getMessage("remind.goods.save.succeed", null, Locale.getDefault());
                rs = new AjaxResult(form, Boolean.TRUE, msg);
            } catch (Exception e) {
                log.error(e);
                String msg = messageSource.getMessage(e.getMessage(), null, Locale.getDefault());
                rs = new AjaxResult(form, Boolean.FALSE, msg);
            }
        }
        return new ResponseEntity<String>(JSONProvider.toJSON(rs),
                responseHeaders, HttpStatus.CREATED);
    }

    @Resource(name = "goodsService")
    private GoodsService goodsService;

    @Autowired
    private MessageSource messageSource;

    private FormBuf getFormBuf(HttpServletRequest request) {
        String buf = HttpCookieUtils.getValue(request, "goodsFormBuf", null);
        if (buf != null) {
            return (FormBuf) JSONProvider.toBean(buf, FormBuf.class);
        }
        return null;
    }

    private void saveFormBuf(HttpServletRequest request
            , HttpServletResponse response, FormBuf buf) {
        String json = JSONProvider.toJSON(buf);
        HttpCookieUtils.setValue(response, null, "goodsFormBuf", json, 60 * 60 * 24);
    }

    public static class GoodsJSON extends Goods {
        /**
         *
         */
        private static final long serialVersionUID = 3533757241983120013L;

        private Brand brand;
        private Category category;

        public Brand getBrand() {
            return brand;
        }

        public void setBrand(Brand brand) {
            this.brand = brand;
        }

        public Category getCategory() {
            return category;
        }

        public void setCategory(Category category) {
            this.category = category;
        }
    }

    public static class FormBuf {

        private String barcode;
        private String goodsId;
        private String brandId;
        private String brandName;
        private String categoryId;
        private String categoryName;
        private String props;
        private double price = 0;

        public double getPrice() {
            return price;
        }

        public void setPrice(double price) {
            this.price = price;
        }

        public String getProps() {
            return props;
        }

        public void setProps(String props) {
            this.props = props;
        }

        public String getBarcode() {
            return barcode;
        }

        public void setBarcode(String barcode) {
            this.barcode = barcode;
        }

        public String getBrandName() {
            return brandName;
        }

        public void setBrandName(String brandName) {
            this.brandName = brandName;
        }

        public String getCategoryName() {
            return categoryName;
        }

        public void setCategoryName(String categoryName) {
            this.categoryName = categoryName;
        }

        public String getGoodsId() {
            return goodsId;
        }

        public void setGoodsId(String goodsId) {
            this.goodsId = goodsId;
        }

        public String getBrandId() {
            return brandId;
        }

        public void setBrandId(String brandId) {
            this.brandId = brandId;
        }

        public String getCategoryId() {
            return categoryId;
        }

        public void setCategoryId(String categoryId) {
            this.categoryId = categoryId;
        }

        public String toJSON() {
            return JSONProvider.toJSON(this);
        }
    }

    public class PropVO extends Properties {
        /**
         *
         */
        private static final long serialVersionUID = -2097790458424942304L;

        private List<PropValue> values;

        public List<PropValue> getValues() {
            return values;
        }

        public void setValues(List<PropValue> values) {
            this.values = values;
        }
    }

}
